<?php

declare(strict_types=1);

namespace app\admin\model;

use think\facade\Db;

class Table
{
    /**
     * 查询数据表 function
     *
     * @param string $databese 数据库名
     * @return array
     */
    public static function query(string $databese): array
    {
        $arr = Db::query(
            "SELECT 
                TABLE_NAME AS 'table', 
                TABLE_COMMENT AS 'comment', 
                TABLE_ROWS AS 'rows' 
            FROM 
                information_schema.tables 
            WHERE 
                table_schema = '$databese';"
        );
        return $arr;
    }

    /**
     * 获取表字段 function
     *
     * @param string $databese 数据库名
     * @param string $table 数据表名
     * @return array
     */
    public static function fields(string $databese, string $table): array
    {
        $arr = Db::query(
            "SELECT
                COLUMN_NAME as 'field',
                DATA_TYPE as 'type',
                COLUMN_DEFAULT as 'default',
                COLUMN_COMMENT as 'comment'
            FROM
                INFORMATION_SCHEMA.COLUMNS 
            WHERE
                TABLE_SCHEMA = '$databese' 
                AND TABLE_NAME = '$table';"
        );
        return $arr;
    }

    /**
     * 创建表 function
     *
     * @param array $data
     * @return array
     */
    public static function create(array $data): array
    {
        $table = $data["table"];
        $comment = $data["comment"];
        $res = Db::query(
            "CREATE TABLE `$table` (
            `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
            PRIMARY KEY (`id`)
          ) ENGINE=InnoDB COMMENT='$comment';"
        );
        return $res;
    }

    /**
     * 更新表 function
     *
     * @param array $data
     * @return array
     */
    public static function update(array $data): array
    {
        $id = $data["id"];
        $table = $data["table"];
        $comment = $data["comment"];
        $res[] = Db::query("ALTER TABLE $id RENAME TO $table;");
        $res[] = Db::query("ALTER TABLE $table COMMENT '$comment';");
        return $res;
    }

    /**
     * 获取单个数据表 function
     *
     * @param string $databese 数据库
     * @param string $table 表名
     * @return array
     */
    public static function find(string $databese, string $table): array
    {
        $res = Db::query(
            "SELECT
                TABLE_NAME AS 'table',
                TABLE_COMMENT AS 'comment' 
            FROM
                INFORMATION_SCHEMA.TABLES 
            WHERE
                TABLE_SCHEMA = '$databese' 
                AND TABLE_NAME = '$table';"
        );
        return $res[0];
    }

    /**
     * 删除表 function
     *
     * @param array|string $id
     * @return boolean
     */
    public static function delete(array|string $id): bool
    {
        if (is_string($id)) {
            Db::query("DROP TABLE $id;");
        } else {
            foreach ($id as $k => $v) {
                Db::query("DROP TABLE $v;");
            }
        }
        return true;
    }

    /**
     * 创建字段 function
     *
     * @param array $data
     * @return array
     */
    public static function create_field(array $data): array
    {
        $sql = sprintf(
            "ALTER TABLE %s ADD `%s` %s%s DEFAULT %s COMMENT '%s';",
            $data["id"],
            $data["field"],
            self::field_type($data["type"], $data["length"]),
            $data["null"] == "null" ? "" : " NOT NULL",
            $data["default"] == "" ? "NULL" : "'" . $data["default"] . "'",
            $data["comment"]
        );
        $res = Db::query($sql);
        return $res;
    }

    /**
     * 字段类型格式化 function
     *
     * @param string $type
     * @param string $length
     * @return string
     */
    protected static function field_type(string $type, string $length): string
    {
        $str = $type;
        if (trim($length)  != "") {
            $str = $str . "(" . $length . ")";
        }
        return $str;
    }

    /**
     * 获取表的某字段信息 function
     *
     * @param string $table
     * @param string $field
     * @return array
     */
    public static function field_find(string $table, string $field): array
    {
        $sql = "SELECT
                    COLUMN_NAME as 'field',
                    DATA_TYPE as 'type',
                    COLUMN_TYPE as 'length',
                    IS_NULLABLE as 'null',
                    COLUMN_DEFAULT as 'default',
                    COLUMN_COMMENT as 'comment'
                FROM
                    INFORMATION_SCHEMA.COLUMNS 
                WHERE
                    TABLE_NAME = '$table' 
                    AND COLUMN_NAME = '$field';";
        $res = Db::query($sql);
        preg_match("/\((.*?)\)/i", $res[0]["length"], $matches);
        if (isset($matches[1])) {
            $res[0]["length"] = $matches[1];
        } else {
            $res[0]["length"] = "";
        }
        $res[0]["default"] = $res[0]["default"] == null ? "" : $res[0]["default"];
        return $res[0];
    }

    /**
     * 修改表的某字段 function
     *
     * @param array $data
     * @return array
     */
    public static function update_field(array $data): array
    {
        $sql = sprintf(
            "ALTER TABLE %s CHANGE `%s` `%s` %s%s DEFAULT %s COMMENT '%s';",
            $data["id"],
            $data["ab"],
            $data["field"],
            self::field_type($data["type"], $data["length"]),
            $data["null"] == "null" ? "" : " NOT NULL",
            $data["default"] == "" ? "NULL" : "'" . $data["default"] . "'",
            $data["comment"]
        );
        $res = Db::query($sql);
        return $res;
    }

    /**
     * 删除表的某字段 function
     *
     * @param string $id
     * @param string $ab
     * @return boolean
     */
    public static function delete_field(string $id, string $ab): bool
    {
        DB::query("ALTER TABLE $id DROP COLUMN $ab;");
        return true;
    }

    /**
     * 获取表所有字段名 function
     *
     * @param string $table
     * @return array
     */
    public static function get_fields(string $table): array
    {
        $res = Db::query(
            "SELECT
                COLUMN_NAME as 'fields',
                COLUMN_COMMENT as 'comments'
            FROM
                INFORMATION_SCHEMA.COLUMNS 
            WHERE
                TABLE_NAME = '$table';"
        );
        return $res;
    }

    /**
     * 创建表单 function
     *
     * @param array $data
     * @return boolean
     */
    public static function build(array $data): bool
    {
        $app_path = app_path(); //当前应用路径
        $name = self::toCamelCase(str_replace(config("database.connections.mysql.prefix"), "", $data["id"])); //大驼峰名
        // 视图路径
        $view_path = $app_path . DIRECTORY_SEPARATOR . "view" . DIRECTORY_SEPARATOR . self::toSnakeCase($name) . DIRECTORY_SEPARATOR;

        // 模型文件
        $model_fiel = $app_path . DIRECTORY_SEPARATOR . "model" . DIRECTORY_SEPARATOR . $name . ".php";
        // 模型命名空间
        $model_namespace = app('http')->getName() . "\\model";
        // 创建模型
        if (file_exists($model_fiel)) {
            if (isset($data["cover"])) {
                self::model($name, "app\\" . $model_namespace, $model_fiel, $data["data"]);
            }
        } else {
            self::model($name, "app\\" . $model_namespace, $model_fiel, $data["data"]);
        }

        // 控制器文件
        $controller_file = $app_path . DIRECTORY_SEPARATOR . "controller" . DIRECTORY_SEPARATOR . $name . ".php";
        // 创建控制器
        if (file_exists($controller_file)) {
            if (isset($data["cover"])) {
                self::controller($name, "app\\" . app('http')->getName() . "\\controller", $controller_file);
            }
        } else {
            self::controller($name,  "app\\" . app('http')->getName() . "\\controller", $controller_file);
        }

        // 创建view
        // 创建query页面
        $view_query_file = $view_path . "query.html";
        if (file_exists($view_query_file)) {
            if (isset($data["cover"])) {
                self::view_query($data, $view_query_file);
            }
        } else {
            self::view_query($data, $view_query_file);
        }
        // 创建create页面
        $view_create_file = $view_path . "create.html";
        if (file_exists($view_create_file)) {
            if (isset($data["cover"])) {
                self::view_create($data, $view_create_file);
            }
        } else {
            self::view_create($data, $view_create_file);
        }

        // 创建update页面
        $view_update_file = $view_path . "update.html";
        if (file_exists($view_update_file)) {
            if (isset($data["cover"])) {
                self::view_update($data, $view_update_file);
            }
        } else {
            self::view_update($data, $view_update_file);
        }

        return true;
    }

    /**
     * 创建视图update function
     *
     * @param array $data
     * @param string $file
     * @return integer|false
     */
    protected static function view_update(array $data, string $file): int|false
    {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        $html = "";
        $script = "";

        foreach ($data["data"] as $k => $v) {
            if (isset($v["table_show"]) && $v["table_show"] == "on") {
                $html .= $v["html"] . "\n";
                $script .= $v["code"] . "\n";
            }
        }
        $content = <<<EOF
<!DOCTYPE html>
{include file="public/link" /}
<blockquote class="layui-elem-quote">
    更新
</blockquote>
<div class="layui-card">
    <div class="layui-card-body">
        <form class="layui-form layui-form-pane" action="">
            $html
            <div class="layui-form-item layui-hide">
                <div class="layui-input-block">
                    <button type="submit" class="layui-btn" lay-submit lay-filter="submit">立即提交</button>
                    <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                </div>
            </div>
        </form>
    </div>
</div>

{include file="public/script" /}

<script>
    layui.use(function () {
        let form = layui.form
        let $ = layui.$
        let layer = layui.layer

        $script

        // 提交事件
        form.on('submit(submit)', function (data) {
            let field = data.field; // 获取表单全部字段值
            let index = layer.load(0);
            $.post("", field, function (res) {
                if (res.code == 0) {
                    layer.msg(res.msg, {
                        icon: 1
                    }, function () {
                        parent.location.reload()
                    })
                } else {
                    layer.msg(res.msg)
                }
                layer.close(index)
            })

            return false; // 阻止默认 form 跳转
        });
    })
</script>
EOF;
        return file_put_contents($file, $content);
    }

    /**
     * 创建视图create function
     *
     * @param array $data
     * @param string $file
     * @return integer|false
     */
    protected static function view_create(array $data, string $file): int|false
    {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        $html = "";
        $script = "";

        foreach ($data["data"] as $k => $v) {
            if (isset($v["table_show"]) && $v["table_show"] == "on") {
                $html .= $v["html"] . "\n";
                $script .= $v["code"] . "\n";
            }
        }
        $content = <<<EOF
<!DOCTYPE html>
{include file="public/link" /}
<blockquote class="layui-elem-quote">
    添加
</blockquote>
<div class="layui-card">
    <div class="layui-card-body">
        <form class="layui-form layui-form-pane" action="">
            $html
            <div class="layui-form-item layui-hide">
                <div class="layui-input-block">
                    <button type="submit" class="layui-btn" lay-submit lay-filter="submit">立即提交</button>
                    <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                </div>
            </div>
        </form>
    </div>
</div>

{include file="public/script" /}

<script>
    layui.use(function () {
        let form = layui.form
        let $ = layui.$
        let layer = layui.layer

        $script

        // 提交事件
        form.on('submit(submit)', function (data) {
            let field = data.field; // 获取表单全部字段值
            let index = layer.load(0);
            $.post("", field, function (res) {
                if (res.code == 0) {
                    layer.msg(res.msg, {
                        icon: 1
                    }, function () {
                        parent.location.reload()
                    })
                } else {
                    layer.msg(res.msg)
                }
                layer.close(index)
            })

            return false; // 阻止默认 form 跳转
        });
    })
</script>
EOF;
        return file_put_contents($file, $content);
    }

    /**
     * 创建视图query function
     *
     * @param array $data 数据
     * @param string $file 文件
     * @return integer|false
     */
    protected static function view_query(array $data, string $file): int|false
    {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }
        $name = self::toSnakeCase($data["id"]);
        $search = "";
        $script = "";
        $cols = "";
        foreach ($data["data"] as $k => $v) {
            if (isset($v["search"]) && $v["search"] == "on") {
                if ($v["search_type"] == "between") {
                    $script .= "layui.laydate.render({
                                elem: '#$k',
                                rangeLinked: true,
                                range: '~',
                                type: 'datetime'
                            })\n";
                    $search .= "<div class=\"layui-form-item\">
                    <label class=\"layui-form-label\">" . $v["title"] . "</label>
                    <div class=\"layui-input-block\">
                        <input type=\"text\" name=\"" . $k . "\" autocomplete=\"off\" id=\"" . $k . "\"
                            placeholder=\" - \" class=\"layui-input\">
                    </div>
                </div>\n";
                } else {
                    $search .= "<div class=\"layui-form-item\">
                    <label class=\"layui-form-label\">" . $v["title"] . "</label>
                    <div class=\"layui-input-block\">
                        <input type=\"text\" name=\"" . $k . "\" autocomplete=\"off\" placeholder=\"请输入" . $v["title"] . "\"
                            class=\"layui-input\">
                    </div>
                </div>\n";
                }
                $px = "false";
                if (isset($v["px"]) && $v["px"] == "on") {
                    $px = "true";
                }
                $hide = "true";
                if (isset($v["list_show"]) && $v["list_show"] == "on") {
                    $hide = "false";
                }
                $cols .= "{ field: '$k', title: '" . $v["title"] . "', sort: $px, hide: $hide },\n";
            }
        }

        $content = <<<EOF
<!DOCTYPE html>
{include file="public/link" /}
<div class="layui-card">
    <div class="layui-card-body">
        <div class="layui-collapse">
            <div class="layui-colla-item">
                <div class="layui-colla-title">搜索</div>
                <div class="layui-colla-content">
                    <form class="layui-form layui-form-pane kb-table-search">
                        $search
                        <div class="layui-form-item">
                            <button class="layui-btn" type="submit" lay-submit lay-filter="search">确认</button>
                            <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="layui-card">
    <div class="layui-card-body">
        <script type="text/html" id="toolbar">
            <div class="layui-btn-container">
                <button class="layui-btn layui-btn-sm" lay-event="add">添加</button>
                <button class="layui-btn layui-btn-sm layui-bg-red" lay-event="dels">删除</button>
            </div>
        </script>
        <script type="text/html" id="barDemo">
            <div class="layui-btn-container">
                <button class="layui-btn layui-btn-xs" lay-event="edit">编辑</button>
                <button class="layui-btn layui-btn-xs layui-bg-red" lay-event="del">删除</button>
            </div>
        </script>
        <table class="layui-hide" id="table" lay-filter="table"></table>
    </div>
</div>


{include file="public/script" /}
<script>
    layui.use(["common"], () => {
        let table = layui.table
        let $ = layui.$
        let common = layui.common
        let form = layui.form

        // 相关接口
        const QUERY_API = "{:url('$name/query')}"
        const CREATE_API = "{:url('$name/create')}"
        const UPDATE_API = "{:url('$name/update')}"
        const DELETE_API = "{:url('$name/delete')}"
        // 表格列
        let cols = [[
            { type: 'checkbox' },
            $cols
            { fixed: 'right', title: '操作', minWidth: 125, toolbar: '#barDemo' }
        ]]
        // 渲染表格
        table.render({
            elem: '#table',
            url: QUERY_API,
            method: "post",
            toolbar: '#toolbar',
            defaultToolbar: ['filter', 'exports', 'print', {
                title: '搜索',
                layEvent: 'LAYTABLE_SEARCH',
                icon: 'layui-icon-search'
            }],
            cellMinWidth: 80,
            page: true,
            cols: cols,
            limits: [10, 20, 50, 100],
            autoSort: false // 禁用前端自动排序。
        })
        // 工具栏事件
        table.on('toolbar(table)', function (obj) {
            let id = obj.config.id;
            let checkStatus = table.checkStatus(id);
            let othis = lay(this);
            switch (obj.event) {
                case 'add':
                    common.open_iframe(CREATE_API, "添加")
                    break;
                case 'dels':
                    if (checkStatus.data.length > 0) {
                        let id = [];
                        $.each(checkStatus.data, function (k, v) {
                            id.push(v.id)
                        })
                        common.open_confirm(DELETE_API, { id })
                    } else {
                        layer.msg('请选择要删除的数据')
                    }
                    break;
                case 'LAYTABLE_SEARCH':
                    $(".layui-colla-title").click()
                    break;
            };
        })
        // 触发排序事件 
        table.on('sort(table)', function (obj) {
            let key = obj.field
            let value = obj.type
            table.reload('table', {
                initSort: obj, // 记录初始排序，如果不设的话，将无法标记表头的排序状态。
                where: { // 请求参数（注意：这里面的参数可任意定义，并非下面固定的格式）
                    order: { key, value }
                }
            });
        });
        // 触发单元格工具事件
        table.on('tool(table)', function (obj) { // 双击 toolDouble
            let data = obj.data; // 获得当前行数据
            if (obj.event == 'edit') {
                common.open_iframe(UPDATE_API + "?id=" + data.id, "编辑")
            } else {
                let id = data.id
                common.open_confirm(DELETE_API, { id })
            }
        })
        // 搜索提交
        form.on('submit(search)', function (data) {
            let field = data.field; // 获得表单字段

            let obj = common.search_format(field);
            // 执行搜索重载
            table.reload('table', {
                page: {
                    curr: 1 // 重新从第 1 页开始
                },
                where: { where: obj } // 搜索的字段
            });
            return false; // 阻止默认 form 跳转
        })
        // 其他
        $script

    })
</script>
EOF;
        return file_put_contents($file, $content);
    }

    /**
     * 创建控制器 function
     *
     * @param string $class_name 类名
     * @param string $namespace 命名空间
     * @param string $file 文件
     * @return int|false
     */
    protected static function controller(
        string $class_name,
        string $namespace,
        string $file
    ): int|false {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }
        $content = <<<EOF
<?php

declare(strict_types=1);

namespace $namespace;

use app\common\Curd;

class $class_name extends Curd
{
    /**
     * 构造函数 function
     */
    public function __construct()
    {
        \$this->model = new \app\admin\model\\$class_name;
    }
}
EOF;
        return file_put_contents($file, $content);
    }

    /**
     * 创建模型 function
     *
     * @param string $class_name
     * @param string $namespace
     * @param string $file
     * @param array $data
     * @return integer|false
     */
    protected static function model(
        string $class_name,
        string $namespace,
        string $file,
        array $data
    ): int|false {
        $path = pathinfo($file, PATHINFO_DIRNAME);
        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        $model_fun = "";
        foreach ($data as $k => $v) {
            if (isset($v["search"]) && $v["search"] == "on") {
                $name = self::toCamelCase($k);
                $model_fun .= "public function search" . $name . "Attr(\$query, \$value, \$data){";
                switch ($v["search_type"]) {
                    case "between":
                        $model_fun .= "\$query->whereBetweenTime('$k', \$value[0], \$value[1]);";
                        break;
                    case "like":
                        $model_fun .= "\$query->where('$k', 'like', '%' . \$value . '%');";
                        break;
                    default:
                        $model_fun .= "\$query->where('$k', '=', \$value);";
                };
                $model_fun .= "}";
            }
        }

        $content = <<<EOF
<?php
declare (strict_types = 1);

namespace $namespace;

use think\Model;

class $class_name extends Model
{
    $model_fun
}
EOF;
        return file_put_contents($file, $content);
    }

    /**
     * 大驼峰 function
     *
     * @param string $string
     * @param string $separator
     * @return string
     */
    protected static function toCamelCase(string $string, string $separator = '_'): string
    {
        return str_replace(' ', '', ucwords(str_replace($separator, ' ', $string)));
    }

    /**
     * 小驼峰 function
     *
     * @param string $string
     * @return string
     */
    protected static function toSnakeCase(string $string): string
    {
        $string[0] = strtolower($string[0]);
        return preg_replace_callback('/([A-Z])/', function ($matches) {
            return "_" . strtolower($matches[1]);
        }, $string);
    }
}
